'use strict'

const webSocket = require('nodejs-websocket');
const { web_socket_config, MAX_CLIENT } = require('../config.json');
const { HEART_MESSAGE, SYNC_MESSAGE, ERR_MESSAGE, CAPCITY_FULL } = require('../utils/constant');
const { Room } = require('../model/room');
const { handOfflineProject } = require('../class/device');

class Ws {
    constructor() {
        this.deviceMap = new Map(); // 房间map
        this.aliveTime = 1000 * 5; // 死亡检测时间
        this.timmer = null;
        this.isConnect = 0;
        this.server = webSocket.createServer((conn) => {
            console.log(`${JSON.stringify(conn.headers)}连接客户端连接成功！`)
            conn.on('text', (msg) => {
                try {
                    let data = JSON.parse(msg);
                    console.log(data);
                    // console.log(this.deviceMap.get('aaa'));
                    this.handData(data, conn);
                } catch (_) {
                    console.log(_);
                }
            })

            conn.on('close', () => console.log('连接关闭'));

            conn.on('error', (code, reason) => console.log(`ws连接发生错误:${code},${reason}`));
            // 检测客户端的存货状态---清除死掉的客户端信息
            this.isConnect++;
            if (this.isConnect == 1) {
                this.aliveClient();
            }
        }).listen(web_socket_config.port, web_socket_config.ip,
            () => console.log(`ws服务启动IP:${web_socket_config.ip} 端口:${web_socket_config.port}`))
    }
    // 处理客户端的消息
    handData(data, conn) {
        switch (data.cmd) {
            case 'heart':
                conn.sendText(HEART_MESSAGE);
                break;
            case 'sync_id':
                this.handSyncRoom(data, conn);
                break;
            case 'alive':
                this.handClientAlive(conn.key);
                break;
            case 'news':
                this.handNews(data, conn);
            default:
                conn.sendText(ERR_MESSAGE);
                break;
        }
    }
    /**
     * 处理消息
     * @param {Object} data {buffer: '', filePath: '', type: 'update'}
     * @param {*} conn
     */
    handNews(data, conn_now) {
        const sync_id = data.content.sync_id;
        let clientList = this.deviceMap.get(sync_id);
        console.log(clientList, '--');
        this.server.connections.forEach((conn) => {
            clientList.forEach((deviceInfo) => {
                // 广播给 其他客户端 除了自己
                if (deviceInfo.device_conn_key === conn.key && conn.key !== conn_now.key) {
                    let fileData = JSON.stringify({
                        cmd: 'news',
                        content: {
                            desc: "更新的buffer",
                            project_name: deviceInfo.project_name,
                            project_path: deviceInfo.project_path,
                            ...data.content
                        }
                    })
                    conn.sendText(fileData);
                    console.log(`【${deviceInfo.project_name}】项目广播成功!`);
                }
            })
        })
    }
    /**
     * 处理客户端
     * @param {Object} data
     * {
     *  cmd: 'sync_id',
     *  content: {
     *      sync_id: 'asdas',
     *      project_name: data.project_name,
     *      project_path: data.project_path,
     *      m_id: data.m_id
     *  }
     *}
     * @param {*} conn 
     * @returns 
     */
    handSyncRoom(data, conn) {
        const sync_id = data.content.sync_id;
        // 查看房间列表的连接客户端信息
        let clientList = this.deviceMap.get(sync_id);
        if (clientList == undefined) clientList = [];

        // 容量足够
        if (clientList && clientList.length >= MAX_CLIENT) {
            conn.sendText(CAPCITY_FULL);
            return false;
        }

        clientList.push({
            project_name: data.content.project_name,
            project_path: data.content.project_path,
            m_id: data.content.m_id,
            device_conn_key: conn.key
        })

        this.deviceMap.set(sync_id, clientList);
        console.log('房间号的客户端列表:', clientList);

        conn.sendText(JSON.stringify({
            cmd: 'regist',
            content: {
                desc: "服务端收到房间信息，注册成功!",
                con_key: conn.key,
                m_id: data.content.m_id
            }
        }));
    }
    // 处理死掉的客户端
    aliveClient() {
        let clearRoomList = [];
        this.timmer && clearInterval(this.timmer);
        this.aliveTimmer = setInterval(async () => {
            // 所有房间节点
            for (const item of this.deviceMap) {
                const roomMenberList = item[1];
                let newMenberList = [];
                roomMenberList.forEach(m => {
                    let isAlive = false;
                    this.server.connections.forEach((con) => {
                        if (con.key == m.device_conn_key) {
                            newMenberList.push(m); // 要保留的
                            isAlive = true
                        }
                    })
                    // 不在线的key 记录下来 同步到数据库
                    if (!isAlive) clearRoomList.push(m.device_conn_key);
                })

                console.log(item[0], newMenberList);
                if (newMenberList.length) {
                    this.deviceMap.set(item[0], newMenberList);
                } else {
                    this.deviceMap.delete(item[0]) // map 中清除无客户端的房间key
                }
            }
            // 移除不在线的项目列表
            if (clearRoomList.length) {
                handOfflineProject(clearRoomList);
                clearRoomList = [];
                return;
            };

            console.log('无须清除房间列表');
        }, this.aliveTime);
    }

    static getInstance() {
        if (Ws.instance) {
            return Ws.instance;
        } else {
            Ws.instance = new Ws();
            return Ws.instance;
        }
    }
}

module.exports = new Ws();

// new Ws(); 